

#include <sudoku.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

sdk_list *sdk_list_create(){

  sdk_list *list = SDK_LIST_ALLOC();
  list->next = NULL;
  list->num = 0;
  return list;

}

sdk_list *sdk_list_copy(sdk_list *list){

  sdk_list *copy = sdk_list_create();
  sdk_elem *elem;

  SDK_LIST_TRAV(list, elem){
    sdk_elem *new = SDK_ELEM_ALLOC();
    new->num = elem->num;
    sdk_list_add(copy, new);
  }

  return copy;

}

void sdk_list_copy_dest(sdk_list *dest, sdk_list *src){

  sdk_list *tmp = sdk_list_copy(src);
  memcpy(dest, tmp, sizeof(sdk_list));
  _sdk_memory -= sizeof(sdk_list);
  free((void *) tmp);

}

sdk_elem *sdk_list_remove_elem(sdk_list *list, sdk_elem *elem){

  sdk_elem *next;
  sdk_elem *prev = list;

  SDK_LIST_TRAV(list, next){
    if (next == elem){
      prev->next = next->next;
      return next;
    }
    prev = next;
  }

  return NULL;

}

sdk_elem *sdk_list_remove_num(sdk_list *list, int num){

  sdk_elem *next;

  SDK_LIST_TRAV(list, next){
    if (next->num == num){
      return sdk_list_remove_elem(list, next);
    }
  }

  return NULL;

}

sdk_elem *sdk_list_remove_offset(sdk_list *list, int offset){

  int i = 0;
  sdk_elem *elem;

  SDK_LIST_TRAV(list, elem){
    if (i == offset) return sdk_list_remove_elem(list, elem);
    i++;
  }

  return NULL;

}

sdk_elem *sdk_list_get_elem(sdk_list *list, int offset){

  sdk_elem *next;
  int i = 0;

  SDK_LIST_TRAV(list, next){
    if ( i++ == offset) return next;
  }

  return NULL;

}

sdk_elem *sdk_list_get(sdk_list *list, int num){

  sdk_elem *elem;

  SDK_LIST_TRAV(list, elem){
    if (elem->num == num) return elem;
  }

  return NULL;

}

void sdk_list_add(sdk_list *list, sdk_elem *elem){
  
  if (list->next == NULL){
    list->next = elem;
    elem->next = NULL;
    return;
  }
  
  sdk_elem *next;

  SDK_LIST_TRAV(list, next){
    if (next->next == NULL){
      next->next = elem;
      elem->next = NULL;
      //fprintf(stderr, "[sdk_list_add] prev final elem addr: 0x%08x\n", next);
      return;
    }
  }

}

void sdk_list_add_num(sdk_list *list, int num){

  sdk_elem *elem = SDK_ELEM_ALLOC();
  elem->num = num;
  sdk_list_add(list, elem);

}

int sdk_list_length(sdk_list *list){

  sdk_elem *next;
  int i = 0;

  SDK_LIST_TRAV(list, next){
    i++;
  }

  return i;

}

void sdk_list_destroy(sdk_list *list){

  _sdk_memory -= sizeof(sdk_list);
  free((void *) list);

}

int sdk_list_destroy_elem(sdk_list *list, sdk_elem *elem){

  sdk_elem *rem = sdk_list_remove_elem(list, elem);
  if (rem != NULL){
    _sdk_memory -= sizeof(sdk_elem);
    free((void *) rem);
    return 1;
  }
  return 0;

}

int sdk_list_destroy_num(sdk_list *list, int num){

  sdk_elem *rem = sdk_list_remove_num(list, num);
  if (rem != NULL){
    _sdk_memory -= sizeof(sdk_elem);
    free((void *) rem);
    return 1;
  }
  return 0;

}

void sdk_list_destroy_all(sdk_list *list){

  sdk_list_destroy_elems(list);
  sdk_list_destroy(list);

}

void sdk_list_destroy_elems(sdk_list *list){

  while (sdk_list_length(list) > 0){
    sdk_elem *rem = sdk_list_remove_elem(list, list->next);
    _sdk_memory -= sizeof(sdk_elem);
    free((void *) rem);
  }

}

void _sdk_list_print_sum(sdk_list *list){

  if (list == NULL){
    fprintf(stderr, "List=NULL\n");
    return;
  }

  sdk_elem *next;
  int i = 0;

  fprintf(stderr, "List length: %d\n", (int)sdk_list_length(list));
#ifdef _SDK_PROC_x86_64
  fprintf(stderr, "List start address: 0x%016lx\n", (unsigned long) list);
#else
  fprintf(stderr, "List start address: 0x%08lx\n", (unsigned long) list);
#endif 
  SDK_LIST_TRAV(list, next){
#ifdef _SDK_PROC_x86_64
    fprintf(stderr, "  Elem: %d: address=0x%016lx num=%d\n", i++, 
	    (unsigned long) next, next->num);
#else
    fprintf(stderr, "  Elem: %d: address=0x%08lx num=%d\n", i++, 
	    (unsigned long) next, next->num);
#endif
  }

}

void _sdk_list_print_short_sum(sdk_list *list){

  if (list == NULL){
    fprintf(stderr, "List=NULL\n");
    return;
  }

  sdk_elem *next;

  fprintf(stderr, "Len: %d; ", sdk_list_length(list));
#ifdef _SDK_PROC_x86_64
  fprintf(stderr, "Addr: 0x%016lx; { ", (unsigned long)list);
#else
  fprintf(stderr, "Addr: 0x%08lx; { ", (unsigned long)list);
#endif
  SDK_LIST_TRAV(list, next){
    fprintf(stderr, "%d ", next->num);
  }
  fprintf(stderr, "}\n");

}
